using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Runtime.Serialization;
using System.ComponentModel;


namespace XMas
{
    /// <summary>
    ///  Node that blend between two values from 0 to 1
    /// </summary>
    [Serializable()]
    public class AnimNode_CrossFade : AnimationNode
    {

        #region Fields

        /// <summary>
        /// Number of version of this subnode, used in serialization
        /// </summary>
        /// <remarks>
        /// If you add a new value to serialization, you need to increment this float
        /// This is need to have compatibility with olders version of library
        /// <see cref="WriteXml(System.Xml.XmlWriter)"/>
        /// </remarks>        
        protected const float _SerializationVersionChild = 1.0f;
        /// <summary>
        /// Speed in percent per second when going up value (1), if set 0 it set to automatic, don't use speed
        /// </summary>
        protected float _UpSpeed;
        /// <summary>
        /// Speed in percent per second when going down value (0), if set 0 it set to automatic, don't use speed
        /// </summary>
        protected float _DownSpeed;

        #endregion


        /// <summary>
        /// Contructor
        /// </summary>
        public AnimNode_CrossFade()
        {            
        }


        #region Properties

        /// <summary>
        /// Atribute for _UpSpeed
        /// <see cref="AnimNode_CrossFade._UpSpeed"/>
        /// </summary>
        [CategoryAttribute("CrossFade"), DescriptionAttribute("Speed in percent per second when going up value (1), if set 0 it set to automatic, don't use speed")]
        public float UpSpeed
        {
            get { return _UpSpeed; }
            set { _UpSpeed = value; }
        }

        /// <summary>
        /// Atribute for _DownSpeed
        /// <see cref="AnimNode_CrossFade._DownSpeed"/>
        /// </summary>
        [CategoryAttribute("CrossFade"), DescriptionAttribute("Speed in percent per second when going down value (0), if set 0 it set to automatic, don't use speed")]
        public float DownSpeed
        {
            get { return _DownSpeed; }
            set { _DownSpeed = value; }
        }

        #endregion


        # region Protected Members

        /// <summary>
        /// Initialization of node, set initial values
        /// </summary>
        /// <param name="ID">Node ID</param>
        protected override void Initialize(System.Guid ID)
        {
            base.Initialize(ID);
            _strName = "Cross Fade";
            // Adding two items
            AddChild("Element 0", 1.0f);
            AddChild("Element 1", 0);            
            _bFixedChildren = true;
            _UpSpeed = 0;
            _DownSpeed = 0;
            _CategoryName = "Control Nodes";
        }

        #endregion


        # region Public Members

        /// <summary>
        /// EDITOR EVENT: Called by editor when slider move
        /// </summary>
        /// <param name="iNewValue">Value is between 0 and 100</param>
        public override void HandleSliderMove(int iNewValue)
        {
            // int value is between 0 and 100
            _fEditorValue = (float)iNewValue / 100.0f;
        }

        /// <summary>
        /// Used by system when the node need to update his weight
        /// </summary>
        /// <param name="DeltaSeconds">Elapsed time</param>
        public override void UpdateWeights(double DeltaSeconds)
        {
            // Calculate current value
            CalcCurrentValueWithSpeed(GetValue(), (float)DeltaSeconds);

            _animNodeItemList[0]._fLocalWeigth = 1.0f - _fCurrentValue;
            _animNodeItemList[1]._fLocalWeigth = _fCurrentValue;
        }

        /// <summary>
        /// Calculate the new current value from desired value and speed
        /// </summary>
        /// <param name="fDesiredValue"></param>
        /// <param name="DeltaSeconds"></param>
        protected void CalcCurrentValueWithSpeed(float fDesiredValue, float DeltaSeconds)
        {
            // Going up or down
            float fDelta = fDesiredValue - _fCurrentValue;
            // Speed
            float fSpeed = _UpSpeed;
            if (fDelta < 0)
                fSpeed = _DownSpeed;

            // If we have speed
            if (fSpeed > 0 && fDelta != 0)
            {
                // Max delta
                float fMaxDelta = DeltaSeconds * fSpeed;
                if (Math.Abs(fDelta) > fMaxDelta)
                {
                    if (fDelta < 0)
                        fMaxDelta = -fMaxDelta;

                    _fCurrentValue += fMaxDelta;
                }
                else
                    _fCurrentValue = fDesiredValue;
            }
            else
                _fCurrentValue = fDesiredValue;
        }

        /// <summary>
        /// Internal get current value, first try to use reflexion. If no reflexion found use editor value
        /// Override with caution
        /// </summary>
        /// <returns>Value from 0 to 1</returns>
        protected override float GetValue()
        {            
            float fResultValue = base.GetValue();
         
            // TODO: Terminar
            // Clamp to our range (not editor)


            if (fResultValue < 0)
                fResultValue = 0;
            if (fResultValue > 1.0f)
                fResultValue = 1.0f;

            return fResultValue;
        }

        /// <summary>
        /// Used by system after the node update his weight
        /// </summary>
        /// <param name="elapsedTime"></param>
        public override void PostUpdateWeights(TimeSpan elapsedTime)
        {
        }

        #endregion

        
        #region Load/Save XML

        /// <summary>
        /// Function to write in XML format, if you overwrite you must call base class first
        /// </summary>
        /// <remarks>
        /// Be carefully with the save order, it must be the same that read order!!
        /// </remarks>
        /// <param name="writer">Writer to store data</param>
        public override void WriteXml(XmlWriter writer)
        {
            base.WriteXml(writer);

            writer.WriteElementString("SerializationVersionChild", _SerializationVersionChild.ToString(new System.Globalization.CultureInfo("en-US")));
            writer.WriteElementString("UpSpeed", _UpSpeed.ToString(new System.Globalization.CultureInfo("en-US")));
            writer.WriteElementString("DownSpeed", _DownSpeed.ToString(new System.Globalization.CultureInfo("en-US")));     
        }

        /// <summary>
        /// Function to read xml format, if you overwrite you must call base class first
        /// </summary>
        /// <remarks>
        /// Be carefully with the read order, it must be the same that save order!!
        /// </remarks>
        /// <param name="reader">Reader to retrieve data</param>
        public override void ReadXml(XmlReader reader)
        {
            base.ReadXml(reader);

            float SerializationVersionChild = reader.ReadElementContentAsFloat("SerializationVersionChild", reader.NamespaceURI);
            _UpSpeed = reader.ReadElementContentAsFloat("UpSpeed", reader.NamespaceURI);
            _DownSpeed = reader.ReadElementContentAsFloat("DownSpeed", reader.NamespaceURI);
        }

        #endregion
    }
}
